<?php


namespace EasySwoole\EasySwoole;

use App\Exception\ExceptionHandler;

use App\Libs\IpList;
use App\Libs\Redis\RedisTool;
use App\Process\Consumer;
use App\Queue\MyQueue;
use App\Queue\QueueProcess;
use App\Utility\RabitMqQueue;
use EasySwoole\AtomicLimit\AtomicLimit;
use EasySwoole\Component\Process\AbstractProcess;
use EasySwoole\Component\Timer;
use EasySwoole\EasySwoole\AbstractInterface\Event;
use EasySwoole\EasySwoole\Swoole\EventRegister;
use EasySwoole\Component\Di;
use EasySwoole\Http\Request;
use EasySwoole\Http\Response;
use EasySwoole\Jwt\Jwt;
use EasySwoole\ORM\DbManager;
use EasySwoole\ORM\Db\Connection;
use EasySwoole\ORM\Db\Config;
use EasySwoole\RabbitMq\MqQueue as RaMqQueue;
use EasySwoole\EasySwoole\Config as GlobalConfig;
use EasySwoole\Pool\Manager;
use EasySwoole\Queue\Job;
use EasySwoole\RabbitMq\RabbitMqQueueDriver;


class EasySwooleEvent implements Event
{
    public static function initialize()
    {
        date_default_timezone_set('Asia/Shanghai');

        $config = new \EasySwoole\Pool\Config();
        $redisConfig = new \EasySwoole\Redis\Config\RedisConfig(GlobalConfig::getInstance()->getConf('REDIS'));
        \EasySwoole\Pool\Manager::getInstance()->register(new RedisTool($config, $redisConfig), 'redis');


        Di::getInstance()->set('HTTP_GLOBAL_ON_REQUEST', function (Request $request, Response $response) {
            $fd = $request->getSwooleRequest()->fd;
            $ip = ServerManager::getInstance()->getSwooleServer()->getClientInfo($fd)['remote_ip'];

            // 如果当前周期的访问频率已经超过设置的值，则拦截
            // 测试的时候可以将 30 改小，比如 3
            if (IpList::getInstance()->access($ip) > 3) {
                /**
                 * 直接强制关闭连接
                 */
                ServerManager::getInstance()->getSwooleServer()->close($fd);
                // 调试输出 可以做逻辑处理
                echo '被拦截' . PHP_EOL;
                return false;
            }
            // 调试输出 可以做逻辑处理
            echo '正常访问' . PHP_EOL;
            return true;
        });
    }


    public static function mainServerCreate(EventRegister $register)
    {
        // TODO: Implement mainServerCreate() method.
        $config = new Config(GlobalConfig::getInstance()->getConf("MYSQL"));
        DbManager::getInstance()->addConnection(new Connection($config));
        $register->add($register::onWorkerStart, function () {
            //链接预热
            DbManager::getInstance()->getConnection()->__getClientPool()->keepMin();
        });


        //TODO:: 注册redis连接池
        $config = new \EasySwoole\Pool\Config();
        $redisConfig = new \EasySwoole\Redis\Config\RedisConfig(GlobalConfig::getInstance()->getConf('REDIS'));
        Manager::getInstance()->register(new RedisTool($config,$redisConfig),'redis');

        //TODO:: 延迟队列消费进程
        $processConfig= new \EasySwoole\Component\Process\Config();
        $processConfig->setProcessName('testProcess');
        \EasySwoole\Component\Process\Manager::getInstance()->addProcess(new Consumer($processConfig));


        // 配置 队列驱动器
        $driver = new \EasySwoole\Queue\Driver\RedisQueue($redisConfig, 'easyswoole_queue');
        MyQueue::getInstance($driver);
        // 注册一个消费进程
        $processConfig = new \EasySwoole\Component\Process\Config([
            'processName' => 'QueueProcess', // 设置 自定义进程名称
            'processGroup' => 'Queue', // 设置 自定义进程组名称
            'enableCoroutine' => true, // 设置 自定义进程自动开启协程
        ]);
        \EasySwoole\Component\Process\Manager::getInstance()->addProcess(new QueueProcess($processConfig));
        // 模拟生产者，可以在任意位置投递
//        $register->add($register::onWorkerStart, function ($server, $id) {
//            if ($id == 0) {
//                Timer::getInstance()->loop(3000, function () {
//                    $job = new Job();
//                    $job->setJobData(['time' => \time()]);
//                    MyQueue::getInstance()->producer()->push($job);
//                });
//            }
//        });

        //TODO:: RabitMq配置
        $driver = new RabbitMqQueueDriver('127.0.0.1', 5672, 'guest', 'guest',"/");
        RaMqQueue::getInstance($driver);
        $processConfig= new \EasySwoole\Component\Process\Config();
        $processConfig->setProcessGroup('Test');//设置进程组
        $processConfig->setArg(['a'=>123]);//传参
        $processConfig->setRedirectStdinStdout(false);//是否重定向标准io
        $processConfig->setPipeType($processConfig::PIPE_TYPE_SOCK_DGRAM);//设置管道类型
        $processConfig->setEnableCoroutine(true);//是否自动开启协程
        $processConfig->setMaxExitWaitTime(3);//最大退出等待时间
        $processConfig->setProcessName('MqQueueProcessComposer');
        \EasySwoole\Component\Process\Manager::getInstance()->addProcess(new RabitMqQueue($processConfig));

        ###### 配置限流器 ######
        $limit = new AtomicLimit();
        /** 为方便测试，（全局的）限制设置为 10 */
        $limit->setLimitQps(10);
        $limit->attachServer(ServerManager::getInstance()->getSwooleServer());
        Di::getInstance()->set('auto_limiter', $limit);

        // 开启 IP 限流
        IpList::getInstance();
        $class = new class('IpAccessCount') extends AbstractProcess
        {
            protected function run($arg)
            {
                $this->addTick(10 * 1000, function () {
                    /**
                     * 正常用户不会有一秒超过 6 次的api请求
                     * 做列表记录并清空
                     */
                    $list = IpList::getInstance()->accessList(3);
                    // var_dump($list);
                    IpList::getInstance()->clear();
                });
            }
        };

        // 注册 IP 限流自定义进程
        $processConfig = new \EasySwoole\Component\Process\Config();
        $processConfig->setProcessName('IP_LIST');// 设置进程名称
        $processConfig->setProcessGroup('IP_LIST');// 设置进程组名称
        $processConfig->setArg([]);// 传参
        $processConfig->setRedirectStdinStdout(false);// 是否重定向标准io
        $processConfig->setPipeType(\EasySwoole\Component\Process\Config::PIPE_TYPE_SOCK_DGRAM);// 设置管道类型
        $processConfig->setEnableCoroutine(true);// 是否自动开启协程
        $processConfig->setMaxExitWaitTime(3);// 最大退出等待时间
        \EasySwoole\Component\Process\Manager::getInstance()->addProcess(new $class($processConfig));
    }

    public static function onRequest(Request $request, Response $response): bool
    {
        // TODO: Implement onRequest() method.
        return true;
    }

    public static function afterRequest(Request $request, Response $response): void
    {
        // TODO: Implement afterAction() method.
    }
}